<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Chapter 11.  Berkeley DB Concurrent Data Store Applications</title>
    <link rel="stylesheet" href="gettingStarted.css" type="text/css" />
    <meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
    <link rel="start" href="index.html" title="Berkeley DB Programmer's Reference Guide" />
    <link rel="up" href="index.html" title="Berkeley DB Programmer's Reference Guide" />
    <link rel="prev" href="env_faq.html" title="Environment FAQ" />
    <link rel="next" href="cam_fail.html" title="Handling failure in Data Store and Concurrent Data Store applications" />
  </head>
  <body>
    <div xmlns="" class="navheader">
      <div class="libver">
        <p>Library Version 12.1.6.2</p>
      </div>
      <table width="100%" summary="Navigation header">
        <tr>
          <th colspan="3" align="center">Chapter 11.  Berkeley DB Concurrent Data Store
        Applications </th>
        </tr>
        <tr>
          <td width="20%" align="left"><a accesskey="p" href="env_faq.html">Prev</a> </td>
          <th width="60%" align="center"> </th>
          <td width="20%" align="right"> <a accesskey="n" href="cam_fail.html">Next</a></td>
        </tr>
      </table>
      <hr />
    </div>
    <div class="chapter" lang="en" xml:lang="en">
      <div class="titlepage">
        <div>
          <div>
            <h2 class="title"><a id="cam"></a>Chapter 11.  Berkeley DB Concurrent Data Store
        Applications </h2>
          </div>
        </div>
      </div>
      <div class="toc">
        <p>
          <b>Table of Contents</b>
        </p>
        <dl>
          <dt>
            <span class="sect1">
              <a href="cam.html#cam_intro">Concurrent Data Store
        introduction</a>
            </span>
          </dt>
          <dt>
            <span class="sect1">
              <a href="cam_fail.html">Handling failure in Data Store and Concurrent Data Store applications</a>
            </span>
          </dt>
          <dt>
            <span class="sect1">
              <a href="cam_app.html">Architecting Data Store and Concurrent Data Store applications</a>
            </span>
          </dt>
        </dl>
      </div>
      <div class="sect1" lang="en" xml:lang="en">
        <div class="titlepage">
          <div>
            <div>
              <h2 class="title" style="clear: both"><a id="cam_intro"></a>Concurrent Data Store
        introduction</h2>
            </div>
          </div>
        </div>
        <p>
        It is often desirable to have concurrent read-write access
        to a database when there is no need for full recoverability or
        transaction semantics. For this class of applications,
        Berkeley DB provides interfaces supporting deadlock-free,
        multiple-reader/single writer access to the database. This
        means that at any instant in time, there may be either
        multiple readers accessing data or a single writer modifying
        data. The application is entirely unaware of which is
        happening, and Berkeley DB implements the necessary locking
        and blocking to ensure this behavior.
    </p>
        <p>
        To create Berkeley DB Concurrent Data Store applications,
        you must first initialize an environment by calling <a href="../api_reference/C/envopen.html" class="olink">DB_ENV-&gt;open()</a>.
        You must specify the <a href="../api_reference/C/envopen.html#envopen_DB_INIT_CDB" class="olink">DB_INIT_CDB</a> and <a href="../api_reference/C/envopen.html#envopen_DB_INIT_MPOOL" class="olink">DB_INIT_MPOOL</a> flags
        to that method. It is an error to specify any of the other
        <a href="../api_reference/C/envopen.html" class="olink">DB_ENV-&gt;open()</a> subsystem or recovery configuration flags, for
        example, <a href="../api_reference/C/envopen.html#envopen_DB_INIT_LOCK" class="olink">DB_INIT_LOCK</a>, <a href="../api_reference/C/envopen.html#envopen_DB_INIT_TXN" class="olink">DB_INIT_TXN</a> or <a href="../api_reference/C/envopen.html#envopen_DB_RECOVER" class="olink">DB_RECOVER</a> All
        databases must, of course, be created in this environment by
        using the <a href="../api_reference/C/dbcreate.html" class="olink">db_create()</a> function or <a href="../api_reference/CXX/db.html" class="olink">Db</a> constructor,
        and specifying the environment as an argument.
    </p>
        <p>
        Berkeley DB performs appropriate locking so that safe
        enforcement of the deadlock-free,
        multiple-reader/single-writer semantic is transparent to the
        application. However, a basic understanding of Berkeley DB
        Concurrent Data Store locking behavior is helpful when writing
        Berkeley DB Concurrent Data Store applications.
    </p>
        <p>
        Berkeley DB Concurrent Data Store avoids deadlocks without
        the need for a deadlock detector by performing all locking on
        an entire database at once (or on an entire environment in the
        case of the <a href="../api_reference/C/envset_flags.html#set_flags_DB_CDB_ALLDB" class="olink">DB_CDB_ALLDB</a> flag), and by ensuring that at any
        given time only one thread of control is allowed to
        simultaneously hold a read (shared) lock and attempt to
        acquire a write (exclusive) lock.
    </p>
        <p>
        All open Berkeley DB cursors hold a read lock, which serves
        as a guarantee that the database will not change beneath them;
        likewise, all non-cursor <a href="../api_reference/C/dbget.html" class="olink">DB-&gt;get()</a> operations temporarily
        acquire and release a read lock that is held during the actual
        traversal of the database. Because read locks will not
        conflict with each other, any number of cursors in any number
        of threads of control may be open simultaneously, and any
        number of <a href="../api_reference/C/dbget.html" class="olink">DB-&gt;get()</a> operations may be concurrently in
        progress.
    </p>
        <p>
        To enforce the rule that only one thread of control at a
        time can attempt to upgrade a read lock to a write lock,
        however, Berkeley DB must forbid multiple cursors from
        attempting to write concurrently. This is done using the
        <a href="../api_reference/C/dbcursor.html#cursor_DB_WRITECURSOR" class="olink">DB_WRITECURSOR</a> flag to the <a href="../api_reference/C/dbcursor.html" class="olink">DB-&gt;cursor()</a> method. This is the
        only difference between access method calls in Berkeley DB
        Concurrent Data Store and in the other Berkeley DB products.
        The <a href="../api_reference/C/dbcursor.html#cursor_DB_WRITECURSOR" class="olink">DB_WRITECURSOR</a> flag causes the newly created cursor to
        be a "write" cursor; that is, a cursor capable of performing
        writes as well as reads. Only cursors thus created are
        permitted to perform write operations (either deletes or
        puts), and only one such cursor can exist at any given
        time.
    </p>
        <p>
        Any attempt to create a second write cursor or to perform a
        non-cursor write operation while a write cursor is open will
        block until that write cursor is closed. Read cursors may open
        and perform reads without blocking while a write cursor is
        extant. However, any attempts to actually perform a write,
        either using the write cursor or directly using the <a href="../api_reference/C/dbput.html" class="olink">DB-&gt;put()</a> or
        <a href="../api_reference/C/dbdel.html" class="olink">DB-&gt;del()</a> methods, will block until all read cursors are closed.
        This is how the multiple-reader/single-writer semantic is
        enforced, and prevents reads from seeing an inconsistent
        database state that may be an intermediate stage of a write
        operation.
    </p>
        <p>
        By default, Berkeley DB Concurrent Data Store does locking
        on a per-database basis. For this reason, using cursors to
        access multiple databases in different orders in different
        threads or processes, or leaving cursors open on one database
        while accessing another database, can cause an application to
        hang. If this behavior is a requirement for the application,
        Berkeley DB should be configured to do locking on an
        environment-wide basis. See the <a href="../api_reference/C/envset_flags.html#set_flags_DB_CDB_ALLDB" class="olink">DB_CDB_ALLDB</a> flag of the
        <a href="../api_reference/C/envset_flags.html" class="olink">DB_ENV-&gt;set_flags()</a> method for more information.
    </p>
        <p>
        With these behaviors, Berkeley DB can guarantee
        deadlock-free concurrent database access, so that multiple
        threads of control are free to perform reads and writes
        without needing to handle synchronization themselves or having
        to run a deadlock detector. Berkeley DB has no direct
        knowledge of which cursors belong to which threads, so some
        care must be taken to ensure that applications do not
        inadvertently block themselves, causing the application to
        hang and be unable to proceed.
    </p>
        <p>
        As a consequence of the Berkeley DB Concurrent Data Store
        locking model, the following sequences of operations will
        cause a thread to block itself indefinitely:
    </p>
        <div class="orderedlist">
          <ol type="1">
            <li>
            Keeping a cursor open while issuing a <a href="../api_reference/C/dbput.html" class="olink">DB-&gt;put()</a> or
            <a href="../api_reference/C/dbdel.html" class="olink">DB-&gt;del()</a> access method call.
        </li>
            <li>
            Attempting to open a write cursor while another
            cursor is already being held open by the same thread of
            control. Note that it is correct operation for one thread
            of control to attempt to open a write cursor or to perform
            a non-cursor write (<a href="../api_reference/C/dbput.html" class="olink">DB-&gt;put()</a> or <a href="../api_reference/C/dbdel.html" class="olink">DB-&gt;del()</a>) while a write
            cursor is already active in another thread. It is only a
            problem if these things are done within a single thread of
            control -- in which case that thread will block and never
            be able to release the lock that is blocking
            it.
        </li>
            <li>
            Not testing Berkeley DB error return codes (if any
            cursor operation returns an unexpected error, that cursor
            must still be closed).
        </li>
          </ol>
        </div>
        <p>
        If the application needs to open multiple cursors in a
        single thread to perform an operation, it can indicate to
        Berkeley DB that the cursor locks should not block each other
        by creating a Berkeley DB Concurrent Data Store <span class="bold"><strong>group</strong></span>, using <a href="../api_reference/C/envcdsgroup_begin.html" class="olink">DB_ENV-&gt;cdsgroup_begin()</a>.
        This creates a locker ID that is shared by all cursors opened
        in the group.
    </p>
        <p>
        Berkeley DB Concurrent Data Store groups use a <a href="../api_reference/C/txn.html" class="olink">TXN</a> handle
        to indicate the shared locker ID to Berkeley DB calls, and
        call <a href="../api_reference/C/txncommit.html" class="olink">DB_TXN-&gt;commit()</a> to end the group. This is a convenient way to
        pass the locked ID to the calls where it is needed, but should
        not be confused with the real transactional semantics provided
        by Berkeley DB Transactional Data Store. In particular,
        Berkeley DB Concurrent Data Store groups do not provide any
        abort or recovery facilities, and have no impact on durability
        of operations.
    </p>
      </div>
    </div>
    <div class="navfooter">
      <hr />
      <table width="100%" summary="Navigation footer">
        <tr>
          <td width="40%" align="left"><a accesskey="p" href="env_faq.html">Prev</a> </td>
          <td width="20%" align="center"> </td>
          <td width="40%" align="right"> <a accesskey="n" href="cam_fail.html">Next</a></td>
        </tr>
        <tr>
          <td width="40%" align="left" valign="top">Environment FAQ </td>
          <td width="20%" align="center">
            <a accesskey="h" href="index.html">Home</a>
          </td>
          <td width="40%" align="right" valign="top"> Handling failure in Data Store and Concurrent Data Store applications</td>
        </tr>
      </table>
    </div>
  </body>
</html>
